package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseBaseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.controller.CourseAuditController;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author 杨佳畅
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;


    /**
     * 分页搜索查询课程基本信息
     * 1. 是否需要事务
     * 2. 参数合法校验
     * 3. 构建Page对象（MP）
     *
     * @param params 分页参数
     * @param model  搜索参数
     * @return
     */
    @Override
    public PageVO queryCourseBaseList(PageRequestParams params, QueryCourseBaseModel model, Long companyId) {
        // 2.校验分页参数
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 3.构建Page对象
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        // 4.构建查询对象
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        // 根据课程名称查询，模糊查询
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()), CourseBase::getName, model.getCourseName());
        // 根据审核状态查询，精确查询
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()), CourseBase::getAuditStatus, model.getAuditStatus());
        // 根据未删除状态，精确查询
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());
        // 如果传递companyId != OPERATION_FLAG 才会根据机构ID查询
        if (!(ObjectUtils.nullSafeEquals(companyId, CourseAuditController.OPERATION_FLAG))) {
            // 根据公司ID，精准查询
            queryWrapper.eq(CourseBase::getCompanyId, companyId);
        }
        // 排序
        queryWrapper.orderByDesc(CourseBase::getCreateDate);

        // 5.查询数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);
        // 获取数据记录
        List<CourseBase> records = pageResult.getRecords();
        // 获取总条数
        long total = pageResult.getTotal();

        // 将数据转换为DTO
        List<CourseBaseDTO> dtos = Collections.emptyList();
        if (!(CollectionUtils.isEmpty(records))) {
            dtos = new ArrayList<>();
            dtos = CourseBaseConvert.INSTANCE.entity2dtos(records);
        }

        // 6.查询结果封装
        PageVO pageVO = new PageVO<>(dtos, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }

    /**
     * 添加课程基本信息
     *
     * @param dto 课程基本信息DTO封装
     * @return {@link CourseBaseDTO 课程基本信息DTO封装}
     */
    @Override
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {
        // 校验机构ID
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            ExceptionCast.cast(ContentErrorCode.E_120027);
        }

        // 判断课程收费规则，生成合法价格
        checkChargeGeneratePrice(dto);

        // 2.将dto转为po
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);
        // 设置新增课程默认状态为 - 未提交
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());

        // 3.保存数据，判断返回结果
        boolean baseSaveResult = this.save(courseBase);
        if (!baseSaveResult) {
            ExceptionCast.cast(ContentErrorCode.E_120001);
        }

        // 构建课程营销表数据
        CourseMarket courseMarket = CourseMarket.builder().courseId(courseBase.getId()).charge(dto.getCharge()).price(dto.getPrice().floatValue()).build();
        // 保存课程营销数据
        boolean marketSaveResult = courseMarketService.save(courseMarket);
        if (!marketSaveResult) {
            ExceptionCast.cast(ContentErrorCode.E_120110);
        }

        // 5.返回数据库最新数据DTO
        CourseBase poData = this.getById(courseBase.getId());
        // 转为DTO
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(poData);
        // 设置课程收费规则
        resultDTO.setCharge(dto.getCharge());
        // 设置课程价格
        resultDTO.setPrice(dto.getPrice());

        return resultDTO;
    }

    /**
     * 修改课程信息
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        // 校验课程ID
        Long courseBaseId = dto.getCourseBaseId();
        if (ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }
        // 判断课程收费规则，生成合法价格
        checkChargeGeneratePrice(dto);

        // 检查课程是否可被修改
        checkAuditStatus(courseBaseId, dto.getCompanyId());


        // 查询课程营销数据
        CourseMarket courseMarket = getCourseMarketById(dto.getCourseBaseId());

        // 4.将DTO转为PO，这些字段不允许被修改 - companyId、auditStatus、status
        CourseBase coursePo = CourseBaseConvert.INSTANCE.dto2entity(dto);
        coursePo.setCompanyId(null);
        coursePo.setAuditStatus(null);
        coursePo.setStatus(null);

        // 更新课程基础信息
        boolean courseResult = this.updateById(coursePo);
        if (!courseResult) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

        // 更新课程营销数据表
        LambdaUpdateWrapper<CourseMarket> marketUpdateWrapper = new LambdaUpdateWrapper<>();
        marketUpdateWrapper.set(CourseMarket::getCharge, dto.getCharge());

        // 获取课程收费规则
        String charge = dto.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            BigDecimal price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                ExceptionCast.cast(ContentErrorCode.E_120019);
            }
            // 构建更新字段 price
            marketUpdateWrapper.set(CourseMarket::getPrice, price);
        } else {
            // 如果课程为免费，价格赋值为0
            marketUpdateWrapper.set(CourseMarket::getPrice, 0F);
        }
        // 构建更新条件 courseBaseId
        marketUpdateWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        boolean marketResult = courseMarketService.update(marketUpdateWrapper);
        if (!marketResult) {
            ExceptionCast.cast(ContentErrorCode.E_120107);
        }

        // 将修改后的最新数据返回给前端
        CourseBaseDTO resultDTO = getLastCourseBaseDTO(dto, courseBaseId);

        return resultDTO;
    }

    /**
     * 判断课程收费规则，生成合法价格
     */
    private void checkChargeGeneratePrice(CourseBaseDTO dto) {
        // 判断课程收费规则
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            // 价格为空，价格小于等于0的情况
            if (ObjectUtils.isEmpty(dto.getPrice()) || dto.getPrice().floatValue() <= 0) {
                ExceptionCast.cast(ContentErrorCode.E_120019);
            }
        } else {
            // 课程免费，设置课程价格为0
            dto.setPrice(new BigDecimal(0));
        }
    }

    /**
     * 根据课程ID删除课程信息
     *
     * @param courseBaseId
     * @param companyId
     */
    @Override
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {
        // 机构ID不可以为空
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }

        // 检查课程是否可被删除
        checkAuditStatus(courseBaseId, companyId);

        // 删除课程基础信息
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());

        updateWrapper.eq(CourseBase::getId, courseBaseId);

        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120021);
        }
    }

    /**
     * 提交课程
     *
     * @param courseBaseId 课程ID
     * @param companyId    机构ID
     */
    @Override
    @Transactional
    public void commitCourseBase(Long courseBaseId, Long companyId) {
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 检查课程是否可被提交
        checkAuditStatus(courseBaseId, companyId);

        // 修改课程审核状态
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBaseId);
        boolean updateResult = this.update(updateWrapper);
        if (!updateResult) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }

    /**
     * 课程审核 - 运营平台
     *
     * @param dto
     */
    @Override
    @Transactional
    public void approveCourse(CourseBaseDTO dto) {
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper();
        // 根据课程ID，精确查询
        queryWrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        // 根据未删除状态，精确查询
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());
        // 根据已提交状态，精确查询
        queryWrapper.eq(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        int count = this.count(queryWrapper);
        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120026);
        }

        // 运营平台只能给审核状态赋值为，审核通过 / 审核未通过
        String auditStatus = dto.getAuditStatus();
        boolean isApproveStatus = auditStatusPredicate(auditStatus, code -> CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(code) ||
                CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode().equals(code));
        ExceptionCast.cast(!isApproveStatus, ContentErrorCode.E_120016);

        // 修改课程审核信息
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, auditStatus);
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        boolean updateResult = this.update(updateWrapper);
        if (!updateResult) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

    }

    /**
     * 根据ID查询课程信息
     *
     * @param courseBaseId 课程ID
     * @param companyId    公司ID
     * @return {@link CourseBaseDTO 课程信息DTO}
     */
    @Override
    public CourseBaseDTO getCourseBaseById(Long courseBaseId, Long companyId) {
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 根据课程ID & 机构ID查询课程基础信息
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);
        // 查询课程营销信息
        CourseMarket courseMarket = getCourseMarketById(courseBaseId);

        // 转换并封装营销数据
        CourseBaseDTO dto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        dto.setCharge(courseMarket.getCharge());
        dto.setPrice(new BigDecimal(courseMarket.getPrice()));
        return dto;
    }

    /**
     * 根据课程ID和机构ID查询课程基本信息
     *
     * @param courseBaseId 课程ID
     * @param companyId    机构ID
     * @return {@link CourseBase 课程基本信息}
     */
    private CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> baseQueryWrapper = new LambdaQueryWrapper();
        baseQueryWrapper.eq(CourseBase::getId, courseBaseId);
        baseQueryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase courseBase = this.getOne(baseQueryWrapper);
        // 课程信息为空或课程被删除，都需要异常处理
        if (ObjectUtils.isEmpty(courseBase) || !(CommonEnum.USING_FLAG.getCodeInt().equals(courseBase.getStatus()))) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }

        return courseBase;
    }

    /**
     * 根据课程ID，查询课程营销信息
     *
     * @param courseBaseId 课程ID
     * @return {@link CourseMarket 课程营销信息}
     */
    private CourseMarket getCourseMarketById(Long courseBaseId) {
        // 根据课程ID，构建查询条件
        LambdaQueryWrapper<CourseMarket> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        CourseMarket market = courseMarketService.getOne(baseQueryWrapper);

        // 判断营销信息是否存在
        if (ObjectUtils.isEmpty(market)) {
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        return market;
    }

    /**
     * 返回课程最新数据
     *
     * @param dto
     * @param id
     * @return
     */
    private CourseBaseDTO getLastCourseBaseDTO(CourseBaseDTO dto, Long id) {
        CourseBase po = this.getById(id);
        // 将PO转换为DTO
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
        return resultDTO;
    }

    /**
     * 检查课程状态，用于修改、删除、提交课程
     *
     * @param companyId    机构ID
     * @param courseBaseId 课程ID
     */
    private void checkAuditStatus(Long courseBaseId, Long companyId) {
        // 根据课程ID & 机构ID，查询课程基础信息
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);
        // 审核未通过、未提交 true
        // 已提交、课程已发布、审核通过、课程已下线 false
        boolean isCommitStatus = auditStatusPredicate(courseBase.getAuditStatus(), code -> CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(code) ||
                CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode().equals(code));
        // 若不是未提交、审核未通过这两种状态，则抛出异常
        ExceptionCast.cast(!isCommitStatus, ContentErrorCode.E_120015);
    }

    /**
     * 对课程审核状态的断言
     *
     * @param auditStatus 审核状态
     * @param predicate   断言
     * @return
     */
    private boolean auditStatusPredicate(String auditStatus, Predicate<String> predicate) {
        return predicate.test(auditStatus);
    }

}
